////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "SmegEditorFrame.h"

#include <iostream>

#include <wx/propgrid/advprops.h>

#include <SmegLight/Light/LightSystem.hpp>
#include <SmegCore/Entity/EntityManager.hpp>

#include "ConvexHullCreatorDialog.h"

#include "../ObjectHandler/ObjectHandlerFactory.hpp"

#include "../tinyxml2/tinyxml2.h"

////////////////////////////////////////////////////////////
/// Defines
////////////////////////////////////////////////////////////
#define XML_PROJECT         "Project"
#define XML_PARAM           "Param"
#define XML_GROUP           "Group"
#define XML_GLOBAL_CATEGORY "GlobalCategory"
#define XML_CATEGORY        "Category"
#define XML_CONTENT         "Content"
#define XML_OBJECT          "Object"
#define XML_PROPERTY        "Property"
#define XML_PROPERTY_SET    "PropertySet"

#define XML_ATTR_NAME       "name"
#define XML_ATTR_CLASS      "class"
#define XML_ATTR_LABEL      "label"
#define XML_ATTR_VALUE      "value"
#define XML_ATTR_CHOICES    "choices"
#define XML_ATTR_ICON       "icon"
#define XML_ATTR_RED        "r"
#define XML_ATTR_GREEN      "g"
#define XML_ATTR_BLUE       "b"
#define XML_ATTR_ALPHA      "a"

#define GROUP_ICON          wxT( "data/icons/group.png" )
#define GROUP_ICON_ID       0
    
#define PROJECT_TITLE       wxT( "Project" )
#define PROJECT_ICON        wxT( "data/icons/project.png" )
#define PROJECT_ICON_ID     1

#define COMPONENTS_TITLE    wxT( "Components" )
#define COMPONENTS_ICON     wxT( "data/icons/components.png" )
#define COMPONENTS_ICON_ID  2

////////////////////////////////////////////////////////////
/// Construct the SmegEditorFrame
////////////////////////////////////////////////////////////
SmegEditorFrame::SmegEditorFrame( wxWindow* _pParent ) :
    SmegEditorFrameGUI( _pParent ),
    m_pCurrentObjectProp( NULL ),
    m_bProjectModified(false),
    m_CurrentHandlers(),
    m_CopyCutHandlers(),
    m_CurrentProjectFilename( wxEmptyString ),
    m_ComponentsIcons( 20, 20, true, 0 )
{
    m_bDoesUpdateHandlers = false;
    wxInitAllImageHandlers();

    // Object Handlers factory
    ObjectHandlerFactory::GetInstance()->Init();

    // SFML Canvas
    m_pEditorCanvas = new SmegEditorCanvas(this, wxID_ANY);
    m_canvasLayout->Add( m_pEditorCanvas, 1, wxEXPAND | wxALL, 0, 0 );

    // PropertyGrid
    m_pPropertyGrid = new wxPropertyGrid(m_rightPanel, 
        wxID_OBJECT_PROPERTY,
        wxDefaultPosition,
        wxDefaultSize,
        //wxPG_AUTO_SORT |
        wxPG_BOLD_MODIFIED |
        wxPG_SPLITTER_AUTO_CENTER |
        wxPG_DEFAULT_STYLE);

    m_rightLayout->Add( m_pPropertyGrid, 1, wxEXPAND | wxALL, 0 );
    
    // Connect Events
    this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(SmegEditorFrame::OnClose));
    this->Connect(wxID_OBJECT_PROPERTY, wxEVT_PG_CHANGED, wxPropertyGridEventHandler(SmegEditorFrame::OnPropertyChanged));
    this->Connect(wxID_OBJECT_PROPERTY, wxEVT_PG_DOUBLE_CLICK, wxPropertyGridEventHandler(SmegEditorFrame::OnPropertyDoubleClick));
    
    m_ComponentsIcons.Add( wxBitmap( GROUP_ICON, wxBITMAP_TYPE_PNG ) );
    m_ComponentsIcons.Add( wxBitmap( PROJECT_ICON, wxBITMAP_TYPE_PNG ) );
    m_ComponentsIcons.Add( wxBitmap( COMPONENTS_ICON, wxBITMAP_TYPE_PNG ) );
    m_projectTreeCtrl->SetImageList( &m_ComponentsIcons );
    m_componentsTreeCtrl->SetImageList( &m_ComponentsIcons );

    SetIcon( wxIcon( PROJECT_ICON, wxBITMAP_TYPE_PNG ) );

    // Project
    m_projectTreeCtrl->AddRoot( wxT("Untitled : ") PROJECT_TITLE, PROJECT_ICON_ID );
    SetProjectModified( false );

    SetFocus();
}

////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
SmegEditorFrame::~SmegEditorFrame() {
}

////////////////////////////////////////////////////////////
/// Call UpdateAndRender on the handlers
////////////////////////////////////////////////////////////
void SmegEditorFrame::UpdateAndRenderHandlers() {
    if ( m_bDoesUpdateHandlers ) {
        for ( td_handlerMap::iterator it = m_AllHandlers.begin(); it != m_AllHandlers.end(); ++it ) {
            it->second->Update();
        }
    }
    for ( td_handlerMap::iterator it = m_AllHandlers.begin(); it != m_AllHandlers.end(); ++it ) {
        it->second->Render();
    }
}

////////////////////////////////////////////////////////////
/// Parse a property
////////////////////////////////////////////////////////////
void SmegEditorFrame::ParseProperty( tinyxml2::XMLElement* _pPropertyElement, SmegEditorFrame::SmegProperty& _PropertyToFill ) {
    const tinyxml2::XMLAttribute * attr = _pPropertyElement->FirstAttribute();
    wxString attrName;

    while (attr) {
        attrName = attr->Name();

        if ( XML_ATTR_CLASS == attrName ) {
            _PropertyToFill.m_ClassName = attr->Value();
        } else if ( XML_ATTR_LABEL == attrName ) {
            _PropertyToFill.m_Label = attr->Value();
        } else if ( XML_ATTR_NAME == attrName ) {
            _PropertyToFill.m_Name = attr->Value();
        } else if ( XML_ATTR_VALUE == attrName ) {
            _PropertyToFill.m_Value = attr->Value();
        } else if ( XML_ATTR_CHOICES == attrName ) {
            wxString choices = attr->Value();
            wxStringTokenizer tkz(choices, L";");
 
            while ( tkz.HasMoreTokens() )
            {
                _PropertyToFill.m_Choices.Add(tkz.GetNextToken());
            }
        } else {
            _PropertyToFill.m_Attributes.push_back( wxAttribute( attr->Name(), attr->Value() ) );
        }
        
        attr = attr->Next();
    }

    if ( _PropertyToFill.m_Name.empty() ) {
        _PropertyToFill.m_Name = _PropertyToFill.m_Label;
    }
}

////////////////////////////////////////////////////////////
/// Parse a category
////////////////////////////////////////////////////////////
void SmegEditorFrame::ParseCategory( tinyxml2::XMLElement* _pCategoryElement, SmegEditorFrame::td_categoryMap& _CategoryMap ) {
    while (_pCategoryElement) {
        wxString categoryName = _pCategoryElement->Attribute( XML_ATTR_NAME );

        // Create the property vector
        td_propertyVector *itProp = &(_CategoryMap.insert( td_categoryMap::value_type( categoryName, 
                                                                                        td_propertyVector()
                                                                                    ) 
                                                            ).first->second);

        // Get the alone properties
        tinyxml2::XMLElement* propertyElement = _pCategoryElement->FirstChildElement( XML_PROPERTY );
        while (propertyElement) {
            SmegProperty currentProp;

            ParseProperty( propertyElement, currentProp );
            currentProp.m_Set = wxEmptyString;

            itProp->push_back(currentProp);

            propertyElement = propertyElement->NextSiblingElement( XML_PROPERTY );
        }

        // Get the properties in set
        tinyxml2::XMLElement* setElement = _pCategoryElement->FirstChildElement( XML_PROPERTY_SET );
        while (setElement) {
            wxString propertySet = setElement->Attribute( XML_ATTR_NAME );

            propertyElement = setElement->FirstChildElement( XML_PROPERTY );
            while (propertyElement) {
                SmegProperty currentProp;
                        
                ParseProperty( propertyElement, currentProp );
                currentProp.m_Set = propertySet;

                itProp->push_back(currentProp);

                propertyElement = propertyElement->NextSiblingElement( XML_PROPERTY );
            }
            setElement = setElement->NextSiblingElement( XML_PROPERTY_SET );
        }

        _pCategoryElement = _pCategoryElement->NextSiblingElement( XML_CATEGORY );
    }
}

////////////////////////////////////////////////////////////
/// Load all properties of all components
////////////////////////////////////////////////////////////
bool SmegEditorFrame::LoadAllProperties( const wxString& _Filename ) {
    td_categoryMap globalCategoryMap;
    tinyxml2::XMLDocument document;
    document.LoadFile(_Filename.c_str());

    if (document.ErrorID() != tinyxml2::XML_NO_ERROR) {
        return false;
    }
    
    // Create the root of m_componentsTreeCtrl
    wxTreeItemId rootId = m_componentsTreeCtrl->AddRoot( COMPONENTS_TITLE, COMPONENTS_ICON_ID );
    tinyxml2::XMLElement* globalCategoryElement = document.FirstChildElement( XML_GLOBAL_CATEGORY );
    tinyxml2::XMLElement* groupElement = document.FirstChildElement( XML_GROUP );

    // Fill the global category map
    if (globalCategoryElement) {
        tinyxml2::XMLElement* categoryElement = globalCategoryElement->FirstChildElement( XML_CATEGORY );

        ParseCategory( categoryElement, globalCategoryMap );
    }

    // Fill the group
    while (groupElement) {
        wxString groupName = groupElement->Attribute( XML_ATTR_NAME );
        wxString groupIcon = groupElement->Attribute( XML_ATTR_ICON );
        
        tinyxml2::XMLElement* objectElement = groupElement->FirstChildElement( XML_OBJECT );

        // Add the group to m_componentsTreeCtrl
        int groupIconId = GROUP_ICON_ID;
        if ( wxEmptyString != groupIcon ) {
            groupIconId = m_ComponentsIcons.Add( wxBitmap( groupIcon, wxBITMAP_TYPE_PNG ) );
        }
        wxTreeItemId groupId = m_componentsTreeCtrl->AppendItem( rootId, groupName, groupIconId );

        while (objectElement) {
            wxString objectName = objectElement->Attribute( XML_ATTR_NAME );
            wxString objectIcon = objectElement->Attribute( XML_ATTR_ICON );

            // Create the category map
            td_categoryMap *categoryMap = &(m_ObjectPropMap.insert( td_objectPropMap::value_type( objectName, 
                                                                                                td_categoryMap()
                                                                                                ) 
                                                                    ).first->second);

            // Add the object to m_componentsTreeCtrl
            int objectIconId = -1;
            if ( wxEmptyString != objectIcon ) {
                objectIconId = m_ComponentsIcons.Add( wxBitmap( objectIcon, wxBITMAP_TYPE_PNG ) );
            }
            wxTreeItemId objectId = m_componentsTreeCtrl->AppendItem( groupId, objectName, objectIconId );
            BaseObjectHandler* objHandler = ObjectHandlerFactory::GetInstance()->GetObjectHandler( objectName );
            assert( objHandler );
            objHandler->SetIconId( objectIconId );

            // Add the global category
            tinyxml2::XMLElement* globalCategoryPropElement = objectElement->FirstChildElement( XML_GLOBAL_CATEGORY );
            while (globalCategoryPropElement) {
                wxString globalCategoryPropName = globalCategoryPropElement->Attribute( XML_ATTR_NAME );
                td_categoryMap::iterator itCat = globalCategoryMap.find( globalCategoryPropName );

                if ( itCat != globalCategoryMap.end() ) {
                    categoryMap->insert( td_categoryMap::value_type( globalCategoryPropName, 
                                                                        td_propertyVector( itCat->second )
                                                                ) 
                                        );
                } else {
                    return false;
                }

                globalCategoryPropElement = globalCategoryPropElement->NextSiblingElement( XML_GLOBAL_CATEGORY );
            }
            
            // Parse the category
            tinyxml2::XMLElement* categoryPropElement = objectElement->FirstChildElement( XML_CATEGORY );
            ParseCategory( categoryPropElement, *categoryMap );

            objectElement = objectElement->NextSiblingElement( XML_OBJECT );
        }

        groupElement = groupElement->NextSiblingElement( XML_GROUP );
    }

    m_componentsTreeCtrl->Expand(rootId);

    return true;
}
                        
////////////////////////////////////////////////////////////
/// Clear the handler and the properties
////////////////////////////////////////////////////////////
void SmegEditorFrame::ClearSelection() {
    m_ProjectItemSelected = m_projectTreeCtrl->GetRootItem();
    m_pPropertyGrid->Clear();
    m_CurrentHandlers.clear();
    m_pEditorCanvas->ResetSelectedObjects();
}
                        
////////////////////////////////////////////////////////////
/// Clear the project
////////////////////////////////////////////////////////////
void SmegEditorFrame::ClearProject() {
    // Clear the selection
    ClearSelection();

    // Clear the project tree
    m_projectTreeCtrl->DeleteAllItems();
    m_projectTreeCtrl->AddRoot( wxT( "Untitled : " ) PROJECT_TITLE, PROJECT_ICON_ID );

    // Clear the handlers
    for ( td_handlerMap::iterator it = m_AllHandlers.begin();
        it != m_AllHandlers.end();
        ++it ) {
            delete it->second;
    }
    m_AllHandlers.clear();

    // Clear the scene
    smeg::core::EntityManager::GetInstance()->ClearScene();
    smeg::light::LightSystem::GetInstance()->ClearScene();

    SetProjectModified( true );
}
                        
////////////////////////////////////////////////////////////
/// Ask the user if he wants to save the project
////////////////////////////////////////////////////////////
bool SmegEditorFrame::ProjectModifiedDialog() {
    if ( m_bProjectModified ) {
        wxMessageDialog *dial = new wxMessageDialog(NULL,
            wxT("Your project has been modified. Your modifications will be lost. Do you want to save your project ?"), wxT("Save your project"),
            wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING);

        int ret = dial->ShowModal();
        dial->Destroy();

        if ( wxID_CANCEL == ret ) {
            return false;
        } else {
            if ( wxID_YES == ret ) {
                SaveProject();
            }

            return true;
        }
    }

    return true;
}
                        
////////////////////////////////////////////////////////////
/// Set if the project as been modified or is up to date
////////////////////////////////////////////////////////////
void SmegEditorFrame::SetProjectModified( bool _bIsModified ) {
    wxString filenameExt = wxEmptyString;

    if ( wxEmptyString != m_CurrentProjectFilename.GetFullPath() ) {
        filenameExt = wxT( " (" ) + m_CurrentProjectFilename.GetFullPath() + wxT( ")" );
    }

    if ( _bIsModified || 
        ( wxEmptyString == m_CurrentProjectFilename.GetFullPath() && m_projectTreeCtrl->HasChildren( m_projectTreeCtrl->GetRootItem() ) ) ) {
        m_bProjectModified = true;
        this->SetTitle( wxT( "SmegEditor : " ) + GetProjectItemName( m_projectTreeCtrl->GetRootItem() ) + filenameExt + wxT( "*" ) );
    } else {
        m_bProjectModified = false;
        this->SetTitle( wxT( "SmegEditor : " ) + GetProjectItemName( m_projectTreeCtrl->GetRootItem() ) + filenameExt );
    }
}

////////////////////////////////////////////////////////////
/// Get a handler corresponding to the given name
////////////////////////////////////////////////////////////
BaseObjectHandler* SmegEditorFrame::GetHandlerByName( const wxString& _Name ) {
    for ( td_handlerMap::iterator it = m_AllHandlers.begin();
        it != m_AllHandlers.end();
        ++it ) {
        if ( _Name == it->second->GetId() ) {
            return it->second;
        }
    }

    return NULL;
}
                        
////////////////////////////////////////////////////////////
/// Get the name of a project item (the name before the ':')
///
/// \param _Item :      The id of the item we want the name
///
////////////////////////////////////////////////////////////
wxString SmegEditorFrame::GetProjectItemName( wxTreeItemId _Item ) {
    wxString itemText =  m_projectTreeCtrl->GetItemText( _Item );
    wxString beforeClass = itemText.BeforeLast( ':' );

    if ( wxEmptyString == beforeClass ) {
        return itemText;
    } else {
        return beforeClass.BeforeLast( ' ' );
    }
}
                        
////////////////////////////////////////////////////////////
/// Return an available name from the given base name
////////////////////////////////////////////////////////////
wxString SmegEditorFrame::GetAvailableName( const wxString& _BaseName ) {
    td_handlerMap::iterator itMap = m_AllHandlers.find( _BaseName );
    wxString newName = _BaseName;
    int modifName = 0;

    while ( itMap != m_AllHandlers.end() ) {
        newName = _BaseName + wxT(" (") + wxString::Format("%d", modifName) + wxT(")");
        itMap = m_AllHandlers.find( newName );
        ++modifName;
    }

    return newName;
}

////////////////////////////////////////////////////////////
/// Add a new handler
////////////////////////////////////////////////////////////
void SmegEditorFrame::AddHandler( BaseObjectHandler* _pHandler, wxTreeItemId _Parent ) {
    wxString newId = GetAvailableName( _pHandler->GetId() );
    _pHandler->SetId( newId );
    m_AllHandlers.insert( td_handlerMap::value_type( newId, _pHandler ) );

    m_ProjectItemSelected = m_projectTreeCtrl->AppendItem( _Parent, newId + wxT( " : " ) + _pHandler->GetName(), _pHandler->GetIconId() );
    m_projectTreeCtrl->Expand( _Parent );
    m_projectTreeCtrl->SelectItem( m_ProjectItemSelected );

    _pHandler->AddObjectToScene();

    SetProjectModified( true );
}

////////////////////////////////////////////////////////////
/// Remove a handler
////////////////////////////////////////////////////////////
void SmegEditorFrame::RemoveHandler( BaseObjectHandler* _pHandler, wxTreeItemId* _pHandlerItem ) {
    m_AllHandlers.erase( _pHandler->GetId() );

    if ( _pHandlerItem ) {
        m_projectTreeCtrl->Delete( *_pHandlerItem );
    } else {
        RemoveProjectTreeItemsWithText( _pHandler->GetId(), m_projectTreeCtrl->GetRootItem() );
    }

    _pHandler->RemoveObjectFromScene();
    delete _pHandler;

    SetProjectModified( true );
}

////////////////////////////////////////////////////////////
/// Remove handlers
////////////////////////////////////////////////////////////
void SmegEditorFrame::RemoveHandlers( const std::vector< BaseObjectHandler* >& _Handlers ) {
    for ( unsigned i = 0; i < _Handlers.size(); ++i ) {
        RemoveHandler( _Handlers[i] );
    }

    SetProjectModified( true );
}
                        
////////////////////////////////////////////////////////////
/// Fill the PropertyGrid depending on the object given
////////////////////////////////////////////////////////////
bool SmegEditorFrame::FillCategoryProperties( const wxString& _CategoryName, td_propertyVector* _pPropertyVec, BaseObjectHandler* _pHandler ) {
    // Append it
    m_pPropertyGrid->Append( new wxPropertyCategory( _CategoryName ) );

    // For each property in this category
    for (td_propertyVector::iterator itVec = _pPropertyVec->begin();
        itVec != _pPropertyVec->end();
        ++itVec) {
            // Create it and append it
            wxClassInfo* classInfo = wxClassInfo::FindClass( itVec->m_ClassName );

            if ( !classInfo || !classInfo->IsKindOf(wxCLASSINFO(wxPGProperty))) {
                wxMessageBox(
                    wxString::Format(wxT("'%s' is not a valid property class"), itVec->m_ClassName.c_str()),
                    wxT("Wrong property class!!!"),
                    wxOK | wxICON_ERROR,
                    this);

                return false;
            }

            wxPGProperty* pgProp = static_cast<wxPGProperty*>(classInfo->CreateObject());

            pgProp->SetLabel(itVec->m_Label);
            pgProp->SetName(itVec->m_Name);
            wxString endValue = wxEmptyString;
            if ( _pHandler ) {
                if ( itVec->m_Set.empty() ) {
                    endValue = _pHandler->GetValueAsString( itVec->m_Label );
                } else {
                    endValue = _pHandler->GetValueAsString( itVec->m_Set + wxT(".") + itVec->m_Label );
                }
            } 
            
            if ( wxEmptyString == endValue ) {
                endValue = itVec->m_Value;
            }
            pgProp->SetValueFromString( endValue );

            // Add choices
            if ( itVec->m_Choices.size() > 0 ) {
                pgProp->SetChoices( itVec->m_Choices );
                if ( _pHandler ) {
                    pgProp->SetValue( _pHandler->GetChoiceValue( pgProp ) );
                }
            }

            // Add special attributes
            for ( unsigned attr = 0; attr < itVec->m_Attributes.size(); ++attr ) {
                pgProp->SetAttribute( itVec->m_Attributes[attr].m_Name, wxVariant( itVec->m_Attributes[attr].m_Value ) );
            }
                        
            if ( itVec->m_Set.empty() ) {
                m_pPropertyGrid->Append(pgProp);
            } else {
                // Prop is in a set so create (or get) the set and append the prop to it
                wxPGProperty* pgSet = m_pPropertyGrid->GetProperty(itVec->m_Set);

                if (!pgSet) {
                    pgSet = new wxStringProperty(itVec->m_Set, itVec->m_Set, wxT("<composed>"));
                    m_pPropertyGrid->Append(pgSet);
                }

                m_pPropertyGrid->AppendIn( pgSet, pgProp );
            }
    }

    return true;
}

////////////////////////////////////////////////////////////
/// Fill the PropertyGrid depending on the object given
////////////////////////////////////////////////////////////
bool SmegEditorFrame::FillProperties( const wxString& _Object, BaseObjectHandler* _pHandler ) {
    m_pCurrentObjectProp = NULL;
    m_pPropertyGrid->Clear();

    if ( wxEmptyString == _Object ) {
        if ( m_ProjectItemSelected.IsOk() ) {
            m_pPropertyGrid->Append( new wxPropertyCategory( "Base" ) );
            m_pPropertyGrid->Append( new wxStringProperty( "Name", "Name", GetProjectItemName( m_ProjectItemSelected ) ) );

            if ( m_projectTreeCtrl->GetRootItem() == m_ProjectItemSelected ) {
                const sf::Color& sfAmbientCol( smeg::light::LightSystem::GetInstance()->GetAmbientColor() );
                wxColour ambientCol( sfAmbientCol.r, sfAmbientCol.g, sfAmbientCol.b, sfAmbientCol.a );
                m_pPropertyGrid->Append( new wxColourProperty( "Ambient Light", "Ambient Light", ambientCol ) );
                m_pPropertyGrid->Append( new wxFloatProperty( "Alpha Threshold", "Alpha Threshold", smeg::light::LightSystem::GetInstance()->GetAlphaThreshold() ) );
                m_pPropertyGrid->Append( new wxFloatProperty( "Blur Radius", "Blur Radius", smeg::light::LightSystem::GetInstance()->GetBlurRadius() ) );
                m_pPropertyGrid->Append( new wxBoolProperty( "Update Entities", "Update Entities", m_pEditorCanvas->DoesUpdateEntities() ) );
                m_pPropertyGrid->Append( new wxBoolProperty( "Show Quad Tree", "Show Quad Tree", m_pEditorCanvas->DoesShowQuadTree() ) );
                m_pPropertyGrid->Append( new wxBoolProperty( "Show Profiler", "Show Profiler", m_pEditorCanvas->DoesShowProfiler() ) );
                m_pPropertyGrid->Append( new wxBoolProperty( "Update Handlers", "Update Handlers", m_bDoesUpdateHandlers ) );
            }

            return true;
        }
    } else {
        td_objectPropMap::iterator itMap = m_ObjectPropMap.find(_Object);

        if (itMap != m_ObjectPropMap.end()) {
            m_pCurrentObjectProp = &itMap->second;

            m_pPropertyGrid->Append( new wxPropertyCategory( "Base" ) );
            if ( _pHandler ) {
                m_pPropertyGrid->Append( new wxStringProperty( "Name", "Name", _pHandler->GetId() ) );
            } else {
                m_pPropertyGrid->Append( new wxStringProperty( "Name", "Name", "NoName" ) );
            }

            // For each category
            for (td_categoryMap::iterator itCat = itMap->second.begin();
                itCat != itMap->second.end();
                ++itCat) {
                    if ( !FillCategoryProperties( itCat->first, &itCat->second, _pHandler ) ) {
                        return false;
                    }
            }

            return true;
        }
    }

    return false;
}

////////////////////////////////////////////////////////////
/// The selected object was moved
////////////////////////////////////////////////////////////
void SmegEditorFrame::OnObjectChangePosition( const sf::Vector2f& _NewPos ) {
    wxPGProperty* pgX = m_pPropertyGrid->GetProperty("Center.x");
    wxPGProperty* pgY = m_pPropertyGrid->GetProperty("Center.y");
    
    if (pgX) {
        pgX->SetValueFromString(wxString::Format("%f", _NewPos.x));
    }
    if (pgY) {
        pgY->SetValueFromString(wxString::Format("%f", _NewPos.y));
    }

    SetProjectModified( true );
}
                        
////////////////////////////////////////////////////////////
/// The selected object was rotated
///
/// \param _fNewRot :  New rotation of the object
///
////////////////////////////////////////////////////////////
void SmegEditorFrame::OnObjectChangeRotation( float _fNewRot ) {
    wxPGProperty* pgRot = m_pPropertyGrid->GetProperty("Angle");
    
    if (pgRot) {
        pgRot->SetValueFromString(wxString::Format("%f", _fNewRot));
    }

    SetProjectModified( true );
}
                        
////////////////////////////////////////////////////////////
/// Set the selected object as to be copied
///
////////////////////////////////////////////////////////////
void SmegEditorFrame::CopySelected() {
    if ( m_CopyCutHandlers.size() > 0 && !m_bIsCopy ) {
        // Definitely remove the cut handler
        RemoveHandlers( m_CopyCutHandlers );
    }

    m_CopyCutHandlers.clear();
    m_CopyCutHandlers.assign( m_CurrentHandlers.begin(), m_CurrentHandlers.end() );
    m_bIsCopy = true;
}
                        
////////////////////////////////////////////////////////////
/// Set the selected object as to be cut
///
////////////////////////////////////////////////////////////
void SmegEditorFrame::CutSelected() {
    if ( m_CopyCutHandlers.size() > 0 && !m_bIsCopy ) {
        // Definitely remove the cut handler
        RemoveHandlers( m_CopyCutHandlers );
    }

    m_CopyCutHandlers.clear();
    m_CopyCutHandlers.assign( m_CurrentHandlers.begin(), m_CurrentHandlers.end() );
    m_bIsCopy = false;
    
    for ( unsigned i = 0; i < m_CopyCutHandlers.size(); ++i ) {
        m_CopyCutHandlers[i]->RemoveObjectFromScene( false );
        RemoveProjectTreeItemsWithText( m_CopyCutHandlers[i]->GetId(), m_projectTreeCtrl->GetRootItem() );
    }
    m_projectTreeCtrl->UnselectAll();
}
                        
////////////////////////////////////////////////////////////
/// Paste the selected object
///
////////////////////////////////////////////////////////////
void SmegEditorFrame::PasteSelected() {
    if ( m_CopyCutHandlers.size() > 0 ) {
        if ( m_bIsCopy ) {
            for ( unsigned i = 0; i < m_CopyCutHandlers.size(); ++i ) {
                BaseObjectHandler* copy = static_cast<BaseObjectHandler*>(m_CopyCutHandlers[i]->Clone());
                AddHandler( copy, m_projectTreeCtrl->GetRootItem() );
            }
        } else {
            for ( unsigned i = 0; i < m_CopyCutHandlers.size(); ++i ) {
                AddHandler( m_CopyCutHandlers[i], m_projectTreeCtrl->GetRootItem() );
            }
            m_CopyCutHandlers.clear();
        }

        SetProjectModified( true );
    }
}

////////////////////////////////////////////////////////////
/// Move/Copy children
////////////////////////////////////////////////////////////
void SmegEditorFrame::MoveProjectTreeChildren( wxTreeItemId _OldParent, wxTreeItemId _NewParent, bool _bRemoveOld ) {
    wxTreeItemIdValue idValue;
    wxTreeItemId curItem = m_projectTreeCtrl->GetFirstChild( _OldParent, idValue ),
        createdItem;

    while ( curItem.IsOk() ) {
        createdItem = m_projectTreeCtrl->AppendItem( _NewParent, m_projectTreeCtrl->GetItemText( curItem ), m_projectTreeCtrl->GetItemImage( curItem ) );

        MoveProjectTreeChildren( curItem, createdItem, false );

        curItem = m_projectTreeCtrl->GetNextSibling( curItem );
    }

    if ( _bRemoveOld ) {
        m_projectTreeCtrl->Delete( _OldParent );
    }

    SetProjectModified( true );
}
                        
////////////////////////////////////////////////////////////
/// Remove a project item with the specified text
////////////////////////////////////////////////////////////
void SmegEditorFrame::RemoveProjectTreeItemsWithText( const wxString& _ItemText, wxTreeItemId _Item, bool _bRemoveChildren ) {
    wxTreeItemIdValue idValue;
    wxTreeItemId curItem = m_projectTreeCtrl->GetFirstChild( _Item, idValue ),
        nextItem;

    while ( curItem.IsOk() ) {
        nextItem = m_projectTreeCtrl->GetNextSibling( curItem );
        if ( _ItemText == GetProjectItemName( curItem ) ) {
            if ( !_bRemoveChildren ) {
                RemoveProjectTreeItemsWithText( _ItemText, curItem, false );
                MoveProjectTreeChildren( curItem, m_projectTreeCtrl->GetItemParent( curItem ) );
            }

            m_projectTreeCtrl->Delete( curItem );
        } else {
            RemoveProjectTreeItemsWithText( _ItemText, curItem, _bRemoveChildren );
        }

        curItem = nextItem;
    }

    SetProjectModified( true );
}

////////////////////////////////////////////////////////////
/// Remove children
////////////////////////////////////////////////////////////
void SmegEditorFrame::RemoveProjectTreeChildren( wxTreeItemId _OldParent, bool _bRemoveOld ) {
    wxTreeItemIdValue idValue;
    wxTreeItemId curItem = m_projectTreeCtrl->GetFirstChild( _OldParent, idValue ),
        nextItem;
    td_handlerMap::iterator itHandler;

    while ( curItem.IsOk() ) {
        nextItem = m_projectTreeCtrl->GetNextSibling( curItem );
        itHandler = m_AllHandlers.find( GetProjectItemName( curItem ) );

        if ( itHandler != m_AllHandlers.end() ) {
            RemoveHandler( itHandler->second, &curItem );
        } else {
            RemoveProjectTreeChildren( curItem, false );
        }

        curItem = nextItem;
    }

    if ( _bRemoveOld ) {
        itHandler = m_AllHandlers.find( GetProjectItemName( _OldParent ) );
        if ( itHandler != m_AllHandlers.end() ) {
            RemoveHandler( itHandler->second, &_OldParent );
        } else {
            m_projectTreeCtrl->Delete( _OldParent );
        }
    } else {
        m_projectTreeCtrl->DeleteChildren( _OldParent );
    }

    SetProjectModified( true );
}

////////////////////////////////////////////////////////////
/// Parse a project item from a file
////////////////////////////////////////////////////////////
bool SmegEditorFrame::ParseProjectElement( tinyxml2::XMLElement* _pElement, wxTreeItemId _Parent ) {
    if ( _pElement ) {
        wxString elemName = _pElement->Name();
        if ( XML_OBJECT == elemName ) {
            // Create and Init a handler
            BaseObjectHandler* handler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( _pElement->Attribute( XML_ATTR_NAME ) );
            if ( handler && handler->Init( m_pEditorCanvas, _pElement, m_CurrentProjectFilename.GetPath() ) ) {
                handler->PostInit();
                AddHandler( handler, _Parent );

                return ParseProjectElement( _pElement->NextSiblingElement(), _Parent );
            }
        } else if ( XML_GROUP == elemName ) {
            wxTreeItemId objectItem = m_projectTreeCtrl->AppendItem( _Parent, _pElement->Attribute( XML_ATTR_NAME ), GROUP_ICON_ID );
            if ( ParseProjectElement( _pElement->FirstChildElement(), objectItem ) ) {
                return ParseProjectElement( _pElement->NextSiblingElement(), _Parent );
            }
        }

        return false;
    }

    return true;
}
        
////////////////////////////////////////////////////////////
/// Save a project item to a file
////////////////////////////////////////////////////////////
void SmegEditorFrame::SaveItemToProjectFile( std::ofstream& _File, wxTreeItemId _parentItem, const wxString& _Tab ) {
    wxTreeItemIdValue idValue;
    wxTreeItemId curItem = m_projectTreeCtrl->GetFirstChild( _parentItem, idValue );

    td_handlerMap::iterator itHandler;

    while ( curItem.IsOk() ) {
        itHandler = m_AllHandlers.find( GetProjectItemName( curItem ) );

        if ( m_AllHandlers.end() == itHandler ) {
            _File << _Tab << "<" << XML_GROUP << " name=\"" << GetProjectItemName( curItem ) << "\">" << std::endl;
            SaveItemToProjectFile( _File, curItem, _Tab + wxT( "\t" ) );
            _File << _Tab << "</" << XML_GROUP << ">" << std::endl;
        } else {
            _File << itHandler->second->ToXMLString( m_CurrentProjectFilename.GetPath(), _Tab );
        }

        curItem = m_projectTreeCtrl->GetNextSibling( curItem );
    }
}
        
////////////////////////////////////////////////////////////
/// Save a project to a file
////////////////////////////////////////////////////////////
void SmegEditorFrame::SaveProject( bool _bForceDialog ) {
    if ( _bForceDialog || wxEmptyString == m_CurrentProjectFilename.GetFullPath() ) {
        wxFileDialog* fileDlg = new wxFileDialog(this, 
                                                _T("Save your Project..."),
                                                wxEmptyString, wxEmptyString, 
                                                "XML Files (*.xml)|*.xml",
                                                wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
            
        if ( wxID_CANCEL != fileDlg->ShowModal() ) {
            m_CurrentProjectFilename = fileDlg->GetPath();
        }

        fileDlg->Destroy();
    }

    if ( wxEmptyString != m_CurrentProjectFilename.GetFullPath() ) {
        bool savingProgress = false;

        std::ofstream file( m_CurrentProjectFilename.GetFullPath().c_str().AsChar() );

        if ( file.good() ) {
            smeg::light::LightSystem* lightMgr = smeg::light::LightSystem::GetInstance();

            file << "<?xml version=\"1.0\"?>" << std::endl;
            file << "<" << XML_PROJECT << " name=\"" << GetProjectItemName( m_projectTreeCtrl->GetRootItem() ) << "\">" << std::endl;

            file << "\t<" << XML_PARAM << " name=\"Ambient Light\" r=\"" << wxString::Format( "%d", lightMgr->GetAmbientColor().r ) << "\" " <<
                    "g=\"" + wxString::Format( "%d", lightMgr->GetAmbientColor().g ) << "\" " <<
                    "b=\"" + wxString::Format( "%d", lightMgr->GetAmbientColor().b ) << "\" " <<
                    "a=\"" + wxString::Format( "%d", lightMgr->GetAmbientColor().a ) << "\" />" << std::endl;
            file << "\t<" << XML_PARAM << " name=\"Alpha Threshold\" value=\"" << wxString::Format( "%f", lightMgr->GetAlphaThreshold() ) << "\" />" << std::endl;
            file << "\t<" << XML_PARAM << " name=\"Blur Radius\" value=\"" << wxString::Format( "%f", lightMgr->GetBlurRadius() ) << "\" />" << std::endl;
            file << "\t<" << XML_PARAM << " name=\"Update Entities\" value=\"" << ( m_pEditorCanvas->DoesUpdateEntities() ? "true" : "false" ) << "\" />" << std::endl;
            file << "\t<" << XML_PARAM << " name=\"Show Quad Tree\" value=\"" << ( m_pEditorCanvas->DoesShowQuadTree() ? "true" : "false" ) << "\" />" << std::endl;
            file << "\t<" << XML_PARAM << " name=\"Show Profiler\" value=\"" << ( m_pEditorCanvas->DoesShowProfiler() ? "true" : "false" ) << "\" />" << std::endl;

            file << "\t<" << XML_CONTENT << ">" << std::endl;
            SaveItemToProjectFile( file, m_projectTreeCtrl->GetRootItem(), "\t\t" );
            file << "\t</" << XML_CONTENT << ">" << std::endl;

            file << "</" << XML_PROJECT << ">" << std::endl;

            savingProgress = true;
        }

        file.close();

        if ( savingProgress ) {
            SetProjectModified( false );
        } else {
	        wxMessageBox(_T("The Project you created couldn't be saved!\n"),
	                        _T("SmegEditor Error"),
	                        wxOK | wxICON_ERROR,
	                        this);
        }
    }
}
        
////////////////////////////////////////////////////////////
/// Setup the menus items after a selection
////////////////////////////////////////////////////////////
void SmegEditorFrame::SetupMenuAfterSelection() {
    wxArrayTreeItemIds arrayIds;
    unsigned numSelected = m_projectTreeCtrl->GetSelections( arrayIds );

    if ( numSelected > 0 ) {
        wxString projectItemTxt = GetProjectItemName( m_ProjectItemSelected );
        if ( numSelected > 1 || m_AllHandlers.end() != m_AllHandlers.find( projectItemTxt ) ) {
            m_addGroupMenuItem->Enable( false );
            m_addGroupPopupMenu->Enable( false );
            m_removeItemMenuItem->Enable();
            m_removeItemPopupMenu->Enable();
        } else {
            m_addGroupMenuItem->Enable();
            m_addGroupPopupMenu->Enable();
            if ( m_projectTreeCtrl->GetRootItem() == m_ProjectItemSelected ) {
                m_removeItemMenuItem->Enable( false );
                m_removeItemPopupMenu->Enable( false );
            } else {
                m_removeItemMenuItem->Enable();
                m_removeItemPopupMenu->Enable();
            }
        }
    } else {
        m_ProjectItemSelected = m_projectTreeCtrl->GetRootItem();
    }
}

////////////////////////////////////////////////////////////
/// Event handlers
////////////////////////////////////////////////////////////
void SmegEditorFrame::OnNewProject( wxCommandEvent& event ) {
    if ( !ProjectModifiedDialog() ) {
        return;
    }

    ClearProject();
    m_CurrentProjectFilename = wxEmptyString;
    SetProjectModified( false );
}

void SmegEditorFrame::OnOpenProject( wxCommandEvent& event ) {
    if ( !ProjectModifiedDialog() ) {
        return;
    }

    wxFileDialog* fileDlg = new wxFileDialog(this,
                                    _T("Load an existing Project..."),
                                    wxEmptyString,
                                    wxEmptyString,
                                    "XML Files (*.xml)|*.xml",
                                    wxFD_OPEN | wxFD_FILE_MUST_EXIST);

    if ( wxID_CANCEL != fileDlg->ShowModal() ) {
        m_CurrentProjectFilename = fileDlg->GetPath();
        bool openingProgress = false;

        tinyxml2::XMLDocument document;
        document.LoadFile(m_CurrentProjectFilename.GetFullPath().c_str());

        if (document.ErrorID() == tinyxml2::XML_NO_ERROR) {
            tinyxml2::XMLElement* projectElem = document.FirstChildElement( XML_PROJECT );

            if ( projectElem ) {
                smeg::light::LightSystem* lightMgr = smeg::light::LightSystem::GetInstance();
                ClearProject();

                m_projectTreeCtrl->SetItemText( m_projectTreeCtrl->GetRootItem(), projectElem->Attribute( XML_ATTR_NAME ) );

                tinyxml2::XMLElement* paramElem = projectElem->FirstChildElement( XML_PARAM );

                while ( paramElem ) {
                    wxString paramName = paramElem->Attribute( XML_ATTR_NAME );
                    if ( "Ambient Light" == paramName ) {
                        lightMgr->SetAmbientColor( sf::Color(   paramElem->UnsignedAttribute( XML_ATTR_RED ), 
                                                                paramElem->UnsignedAttribute( XML_ATTR_GREEN ), 
                                                                paramElem->UnsignedAttribute( XML_ATTR_BLUE ), 
                                                                paramElem->UnsignedAttribute( XML_ATTR_ALPHA ) ) );
                    } else if ( "Alpha Threshold" == paramName ) {
                        lightMgr->SetAlphaThreshold( paramElem->FloatAttribute( XML_ATTR_VALUE ) );
                    } else if ( "Blur Radius" == paramName ) {
                        lightMgr->SetBlurRadius( paramElem->FloatAttribute( XML_ATTR_VALUE ) );
                    } else if ( "Update Entities" == paramName ) {
                        m_pEditorCanvas->UpdateEntities( paramElem->BoolAttribute( XML_ATTR_VALUE ) );
                    } else if ( "Show Quad Tree" == paramName ) {
                        m_pEditorCanvas->ShowQuadTree( paramElem->BoolAttribute( XML_ATTR_VALUE ) );
                    } else if ( "Show Profiler" == paramName ) {
                        m_pEditorCanvas->ShowProfiler( paramElem->BoolAttribute( XML_ATTR_VALUE ) );
                    }

                    paramElem = paramElem->NextSiblingElement( XML_PARAM );
                }

                openingProgress = ParseProjectElement( projectElem->FirstChildElement( XML_CONTENT )->FirstChildElement(), m_projectTreeCtrl->GetRootItem() );
            }

            for ( td_handlerMap::iterator it = m_AllHandlers.begin();
                it != m_AllHandlers.end();
                ++it ) {
                it->second->PostInit();
            }

            m_projectTreeCtrl->ExpandAll();
            m_projectTreeCtrl->SelectItem( m_projectTreeCtrl->GetRootItem() );
        }

        if ( openingProgress ) {
            SetProjectModified( false );
        } else { 
            m_CurrentProjectFilename = wxEmptyString;
            ClearProject();
	        wxMessageBox(_T("An error occured when opening the project!\n"),
	                        _T("SmegEditor Error"),
	                        wxOK | wxICON_ERROR,
	                        this);
        }
    }

    fileDlg->Destroy();
}

void SmegEditorFrame::OnSaveProject( wxCommandEvent& event ) {
    if ( m_bProjectModified ) {
        SaveProject();
    }
}

void SmegEditorFrame::OnSaveProjectAs( wxCommandEvent& event ) {
    SaveProject( true );
}

void SmegEditorFrame::OnClose( wxCloseEvent& event ) {
    if ( !ProjectModifiedDialog() ) {
        event.Veto();
        return;
    }

    ClearProject();
    Destroy();
}
void SmegEditorFrame::OnQuit( wxCommandEvent& event ) {
	Close(true);
}

void SmegEditorFrame::OnAbout( wxCommandEvent& event ) {
	wxMessageBox(wxString::Format(
	                _T("Smeg Level Editor!\n")
	                _T("\n")
	                _T("By Maxime PIQUOT\n")),
	                _T("About..."),
	                wxOK | wxICON_INFORMATION,
	                this);
}

void SmegEditorFrame::OnProjectItemBeginDrag( wxTreeEvent& event ) {
    wxArrayTreeItemIds arrayIds;
    if ( 1 == m_projectTreeCtrl->GetSelections( arrayIds ) ) {
        m_ProjectItemSelected = event.GetItem();
    } else {
        m_ProjectItemSelected = m_projectTreeCtrl->GetRootItem();
    }

    if ( m_projectTreeCtrl->GetRootItem() != m_ProjectItemSelected ) {
        event.Allow();
    }
}

void SmegEditorFrame::OnProjectItemEndDrag( wxTreeEvent& event ) {
    wxString endItem = GetProjectItemName( event.GetItem() );
    
    if ( m_AllHandlers.find( endItem ) == m_AllHandlers.end() ) {
        wxTreeItemId newItem = m_projectTreeCtrl->AppendItem( event.GetItem(), 
                                                                m_projectTreeCtrl->GetItemText( m_ProjectItemSelected ), 
                                                                m_projectTreeCtrl->GetItemImage( m_ProjectItemSelected ) );
        MoveProjectTreeChildren( m_ProjectItemSelected, newItem );
        m_projectTreeCtrl->Expand( event.GetItem() );

        SetProjectModified( true );
    }
}

void SmegEditorFrame::OnProjectItemAddGroup( wxCommandEvent& event ) {
    wxTextEntryDialog* dlg = new wxTextEntryDialog(this, 
        "Name your group : ", 
        "Add a new group...",
        wxEmptyString,
        wxTextEntryDialogStyle);

    int ret = dlg->ShowModal();
    if ( wxID_OK == ret && !dlg->GetValue().empty() ) {
        m_projectTreeCtrl->AppendItem( m_ProjectItemSelected, dlg->GetValue(), GROUP_ICON_ID );
        m_projectTreeCtrl->Expand( m_ProjectItemSelected );

        SetProjectModified( true );
    }

    dlg->Destroy();
}

void SmegEditorFrame::OnProjectItemRemove( wxCommandEvent& event ) {
    wxArrayTreeItemIds arrayIds;
    unsigned numSelected = m_projectTreeCtrl->GetSelections( arrayIds );
    wxString projectItemTxt = GetProjectItemName( m_ProjectItemSelected );
    td_handlerMap::iterator itHandler = m_AllHandlers.find( projectItemTxt );
    
    if ( numSelected > 1 ) {
        for ( unsigned i = 0; i < numSelected; ++i )  {
            RemoveProjectTreeChildren( arrayIds[i] );
        }
    } else if ( itHandler == m_AllHandlers.end() ) {
        int bMoveChildren = wxID_NO;

        wxMessageDialog* dlg = new wxMessageDialog(this, 
                                            _T("Do you want to remove the group and its children or remove the group and move the children up ?"),
                                            _T("Level Editor"),
                                            wxYES_NO | wxCANCEL | wxICON_QUESTION);
        dlg->SetYesNoLabels("Remove and Move", "Remove");

        bMoveChildren = dlg->ShowModal();
        dlg->Destroy();

        if ( bMoveChildren != wxID_CANCEL ) {
            if ( bMoveChildren == wxID_YES ) {
                MoveProjectTreeChildren( m_ProjectItemSelected, m_projectTreeCtrl->GetItemParent( m_ProjectItemSelected ) );
            } else {
                RemoveProjectTreeChildren( m_ProjectItemSelected );
            }

            SetProjectModified( true );
        }
    } else {
        RemoveHandler( itHandler->second, &arrayIds[0] );
    }
}

void SmegEditorFrame::OnProjectItemSubMenu( wxTreeEvent& event ) {
    wxArrayTreeItemIds arrayIds;
    unsigned numSelected = m_projectTreeCtrl->GetSelections( arrayIds );

    if ( numSelected > 0 ) {
        this->PopupMenu( m_projectPopupMenu, event.GetPoint() );
    }
}

void SmegEditorFrame::OnProjectItemSelected( wxTreeEvent& event ) {
    wxArrayTreeItemIds idsArray;
    unsigned numSelected = m_projectTreeCtrl->GetSelections( idsArray );
    
    ClearSelection();
    if ( 1 == numSelected ) {
        m_ProjectItemSelected = event.GetItem();
        wxString projectItemLabel = GetProjectItemName( m_ProjectItemSelected );
        td_handlerMap::iterator itMap = m_AllHandlers.find( projectItemLabel ); 

        if (itMap != m_AllHandlers.end()) {
            m_CurrentHandlers.push_back( itMap->second );
            m_pEditorCanvas->SetSelectedObject( m_CurrentHandlers[0]->GetObject() );
            FillProperties( m_CurrentHandlers[0]->GetName(), m_CurrentHandlers[0] );
        } else {
            // A group was selected
            FillProperties();
        }
    } else {
        if ( 0 < numSelected ) {
            std::vector< smeg::core::PlaceableObject* > selectedObjs;
            wxString projectItemLabel;
            td_handlerMap::iterator itMap;

            for ( unsigned i = 0; i < numSelected; ++i ) {
                projectItemLabel = GetProjectItemName( idsArray[i] );
                itMap = m_AllHandlers.find( projectItemLabel ); 

                if (itMap != m_AllHandlers.end()) {
                    m_CurrentHandlers.push_back( itMap->second );
                    selectedObjs.push_back( itMap->second->GetObject() );
                }
            }
            m_pEditorCanvas->SetSelectedObjects( selectedObjs );
        }
    }

    SetupMenuAfterSelection();
}

void SmegEditorFrame::OnComponentSelected( wxTreeEvent& event ) {
    wxString componentLabel = m_componentsTreeCtrl->GetItemText( event.GetItem() );
    td_objectPropMap::iterator itMap = m_ObjectPropMap.find(componentLabel);

    // Remove the old handler and clear the property grid
    ClearSelection();
    m_projectTreeCtrl->UnselectAll();

    // TODO Only create an item and fill property when component is dragged into the canvas
    if (itMap != m_ObjectPropMap.end()) {
        // Fill the properties
        FillProperties(componentLabel);
        
        // Create the component
        m_CurrentHandlers.clear();
        m_CurrentHandlers.push_back( ObjectHandlerFactory::GetInstance()->CreateObjectHandler(componentLabel) );

        // Center of the new handler
        sf::Vector2f center;
        if ( m_randomPositionMenuItem->IsChecked() ) {
            center.x = rand() % m_pEditorCanvas->getSize().x - m_pEditorCanvas->getSize().x * 0.5f;
            center.y = rand() % m_pEditorCanvas->getSize().y - m_pEditorCanvas->getSize().y * 0.5f;
        } else {
            center = m_pEditorCanvas->GetViewCenter();
        }

        // Init
        if ( m_CurrentHandlers[0] && m_CurrentHandlers[0]->Init( m_pEditorCanvas, m_pPropertyGrid, center ) ) {
            m_CurrentHandlers[0]->PostInit();
            AddHandler( m_CurrentHandlers[0], m_projectTreeCtrl->GetRootItem() );

            SetProjectModified( true );
        } else {
            ClearSelection();
        }
    }
}

void SmegEditorFrame::OnPropertyChanged( wxPropertyGridEvent& event ) {
    wxString propName = event.GetPropertyName();
    if ( "Name" == propName ) {
        wxString newLabel = event.GetPropertyValue().GetString();

        if ( m_CurrentHandlers.size() > 0 ) {
            td_handlerMap::iterator itMap = m_AllHandlers.find( newLabel );
            if ( m_AllHandlers.end() != itMap) {
                event.GetProperty()->SetValueFromString( wxVariant( m_CurrentHandlers[0]->GetId() ) );
	            wxMessageBox(_T("This name is already taken!\n"),
	                            _T("SmegEditor"),
	                            wxOK | wxICON_ERROR,
	                            this);
                event.Veto();
            } else {
                m_AllHandlers.erase( m_CurrentHandlers[0]->GetId() );

                m_CurrentHandlers[0]->SetId( newLabel );
                m_projectTreeCtrl->SetItemText( m_ProjectItemSelected, newLabel + wxT( " : " ) + m_CurrentHandlers[0]->GetName() );
                m_AllHandlers.insert( td_handlerMap::value_type( newLabel, m_CurrentHandlers[0] ) );
            }
        } else if ( m_ProjectItemSelected.IsOk() ) {
            if ( m_projectTreeCtrl->GetRootItem() == m_ProjectItemSelected ) {
                m_projectTreeCtrl->SetItemText( m_ProjectItemSelected, newLabel + wxT( " : " ) PROJECT_TITLE ); 
                this->SetTitle( wxT( "SmegEditor : " ) + newLabel );
            } else {
                m_projectTreeCtrl->SetItemText( m_ProjectItemSelected, newLabel );
            }
        }
    } else if ( "Ambient Light" == propName ) {
        wxColor newAmbientCol = event.GetPropertyValue().GetAny().As<wxColor>();
        smeg::light::LightSystem::GetInstance()->SetAmbientColor( sf::Color( newAmbientCol.Red(), newAmbientCol.Green(), newAmbientCol.Blue(), newAmbientCol.Alpha() ) );
    } else if ( "Alpha Threshold" == propName ) {
        smeg::light::LightSystem::GetInstance()->SetAlphaThreshold( event.GetPropertyValue().GetAny().As<float>() );
    } else if ( "Blur Radius" == propName ) {
        smeg::light::LightSystem::GetInstance()->SetBlurRadius( event.GetPropertyValue().GetAny().As<float>() );
    } else if ( "Update Entities" == propName ) {
        m_pEditorCanvas->UpdateEntities( event.GetPropertyValue().GetAny().As<bool>() );
    } else if ( "Show Quad Tree" == propName ) {
        m_pEditorCanvas->ShowQuadTree( event.GetPropertyValue().GetAny().As<bool>() );
    } else if ( "Show Profiler" == propName ) {
        m_pEditorCanvas->ShowProfiler( event.GetPropertyValue().GetAny().As<bool>() );
    } else if ( "Update Handlers" == propName ) {
        m_bDoesUpdateHandlers = event.GetPropertyValue().GetAny().As<bool>();
    } else if ( m_CurrentHandlers.size() == 1 ) {
        m_CurrentHandlers[0]->OnPropertyChanged( m_pPropertyGrid, event.GetProperty() );
    }

    SetProjectModified( true );

    event.Skip();
}

void SmegEditorFrame::OnPropertyDoubleClick( wxPropertyGridEvent& event ) {
    if ( m_CurrentHandlers.size() == 1 ) {
        m_CurrentHandlers[0]->OnPropertyDoubleClick( m_pPropertyGrid, event.GetProperty() );
    }
}